﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IGolovkine.Core.Diagnostics;
using System.Threading;
using IGolovkine.Core;

namespace IGolovkine.ShoutCastRipper.Testing.ConnectionRecorder
{
    public class StationClientEventPlayer : IStationClient
    {
        public event EventHandler<ContentStartEventArgs> ContentStart;
        public event EventHandler<ContentEndEventArgs> ContentEnd;
        public event EventHandler<ContentReceivedEventArgs> ContentReceived;
        public event EventHandler<DisconnectedEventArgs> Disconnected;

        private readonly IStationClientEventReader _reader;
        private volatile Thread _readingThread;

        private string _currentTitle;
        private DateTime _connectionTime = DateTime.MaxValue;
        private DateTime _currentTitleStartTime = DateTime.MaxValue;
        private readonly ObjectDisposedCheck _disposedCheck;

        public StationClientEventPlayer(IStationClientEventReader reader)
        {
            Debug.NotDefault(() => reader);
            _reader = reader;
            _disposedCheck = new ObjectDisposedCheck(this);
        }

        public void Connect()
        {
            _disposedCheck.EnsureNotDisposed();
            if (this.IsConnected)
            {
                throw new InvalidOperationException(string.Format("{0} is already connected", this.GetType().Name));
            }
            else
            {
                _readingThread = new Thread(this.Read);
                _readingThread.Name = "Reading Thread";
                _connectionTime = DateTime.Now;
                _readingThread.Start();
            }
        }

        private void Read()
        {
            StationClientEvent ev = null;
            while (this.IsConnected && (ev = _reader.ReadNext()) != null)
            {
                this.DistributeEvent(ev);
            }
        }

        private void DistributeEvent(StationClientEvent ev)
        {
            if (ev is ContentReceivedEventArgs)
            {
                this.OnDataReceived((ContentReceivedEventArgs)ev);
            }
            else if (ev is ContentStartEventArgs)
            {
                this.OnStartContent((ContentStartEventArgs)ev);
            }
            else if (ev is ContentEndEventArgs)
            {
                this.OnContentEnd((ContentEndEventArgs)ev);
            }
            else if (ev is DisconnectedEventArgs)
            {
                this.OnDisconnected((DisconnectedEventArgs)ev);
            }
            else
            {
                throw new ArgumentException(string.Format("Invalid Station Client event '{0}'", ev.GetType().Name));
            }
        }

        public void Disconnect()
        {
            if (this.IsConnected)
            {
                if (Thread.CurrentThread != _readingThread)
                {
                    _readingThread.Join();
                }

                _currentTitleStartTime = DateTime.MaxValue;
                _connectionTime = DateTime.MaxValue;
                _currentTitle = null;
                _readingThread = null;
            }
            else
            {
                throw new InvalidOperationException(string.Format("{0} is not connected", this.GetType().Name));
            }
        }

        public bool IsConnected
        {
            get { return _readingThread != null; }
        }

        public string CurrentTitle
        {
            get { return _currentTitle; }
        }

        public DateTime CurrentTitleStartTime
        {
            get { return _currentTitleStartTime; }
        }

        public DateTime ConnectionTime
        {
            get { return _connectionTime; }
        }

        protected virtual void OnStartContent(ContentStartEventArgs args)
        {
            _currentTitleStartTime = DateTime.Now;

            if (this.ContentStart != null)
            {
                this.ContentStart(this, args);
            }
        }

        protected virtual void OnContentEnd(ContentEndEventArgs args)
        {
            if (this.ContentEnd != null)
            {
                this.ContentEnd(this, args);
            }
        }

        protected virtual void OnDisconnected(DisconnectedEventArgs args)
        {
            if (this.Disconnected != null)
            {
                this.Disconnected(this, args);
            }
        }

        protected virtual void OnDataReceived(ContentReceivedEventArgs args)
        {
            if (this.ContentReceived != null)
            {
                this.ContentReceived(this, args);
            }
        }

        public void Dispose()
        {
            _disposedCheck.Dispose();
            if (this.IsConnected)
            {
                this.Disconnect();
            }
        }
    }
}
